﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;

namespace GArphics
{
    /// <summary>
    /// Node-class defines the structure of the nodes, used in the binary tree.
    /// </summary>
    public class Node
    {
        /// <summary>
        /// Operator associated with the node. Can be null if Operand or Value is defined.
        /// </summary>
        public Operators Operator = Operators.NULL;
        /// <summary>
        /// Operand associated with the node. Can be null if Value or Operator is defined.
        /// </summary>
        public Operands Operand = Operands.NULL;
        /// <summary>
        /// Left child-node.
        /// </summary>
        public Node LeftChild = null;
        /// <summary>
        /// Right child-node.
        /// </summary>
        public Node RightChild = null;
        /// <summary>
        /// Constant value associated with the node. Can be null if Operand or Operator is defined.
        /// </summary>
        public double Value = double.NaN;

        /// <summary>
        /// Empty constructor. Everything is se to null. This node will only return the FailValue defined in the Operator-class, if no
        /// other Operator, Operand or Value is defined later.
        /// </summary>
        public Node()
        {
            Operator = Operators.NULL;
            Operand = Operands.NULL;
            LeftChild = null;
            RightChild = null;
            Value = double.NaN;
        }

        public Node(Operators eOperator)
        {
            Operator = eOperator;
            Operand = Operands.NULL;
            LeftChild = null;
            RightChild = null;
            Value = double.NaN;
        }

        public Node(Operators eOperator, Node oLeftChild, Node oRightChild)
        {
            Operator = eOperator;
            Operand = Operands.NULL;
            LeftChild = oLeftChild;
            RightChild = oRightChild;
            Value = double.NaN;
        }

        public Node(double dValue)
        {
            Operator = Operators.NULL;
            Operand = Operands.VALUE;
            LeftChild = null;
            RightChild = null;
            Value = dValue;
        }

        public Node(Operands eOperand)
        {
            Operator = Operators.NULL;
            Operand = eOperand;
            LeftChild = null;
            RightChild = null;
            Value = double.NaN;
        }

        /// <summary>
        /// Calculated the result of the function defined by the node and its child-nodes.
        /// </summary>
        /// <param name="X">X-coordinate</param>
        /// <param name="Y">Y-coordinate</param>
        /// <returns>Product of the function.</returns>
        public double GetValue(double X, double Y)
        {
            if (Operand != Operands.NULL) //If no operator is defined, but operator has been, the value defined by the operator shall be used.
            {
                if (Operand == Operands.X)
                {
                    return X;
                }
                else if (Operand == Operands.Y)
                {
                    return Y;
                }
                else if (Operand == Operands.VALUE)
                {
                    return Value;
                }
            }

            double dLeftResult = GArphics.Operator.FailValue;
            double dRightResult = GArphics.Operator.FailValue;

            dLeftResult = LeftChild.GetValue(X, Y);

            if (GArphics.Operator.SecondOperandNeeded[(int)Operator])
                dRightResult = RightChild.GetValue(X, Y);

            return GArphics.Operator.GetValue(Operator, dLeftResult, dRightResult);
        }

        /// <summary>
        /// Creates a seperate copy of the current node and all of the child-nodes.
        /// </summary>
        /// <returns>Copy of the node.</returns>
        public Node Copy()
        {
            Node oNewNode = new Node();

            oNewNode.Operand = Operand;
            oNewNode.Operator = Operator;
            oNewNode.Value = Value;

            if (this.LeftChild != null)
                oNewNode.LeftChild = this.LeftChild.Copy();
            if (this.RightChild != null)
                oNewNode.RightChild = this.RightChild.Copy();

            return oNewNode;
        }
    }
}
